/*This class represents an observable object, or "data" in the model-view paradigm.*/

package serverP;

import Figuras.*;
import conex.ClientInt;
import conex.RemoteObservable;
import conex.ServerInt;
import java.awt.Color;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import java.util.TreeMap;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author Sandro
 */
public class Server implements ServerInt, Runnable {

   private ServerInt stub;
   private CargadorArchivo t;
   private Thread hilo;
   private boolean flagDeHilo = false;
   private RemoteObservable listaDeClientes = new RemoteObservable();//Composition
   private MenuServer menu;
   private String juego = null;
   private Lienzo lienzo;
   private TreeMap <String,Figura> rel = new TreeMap <String,Figura>();
   private Registry registry;
   private final Color colores[] = {
        Color.cyan, Color.yellow, Color.blue,
        Color.green, Color.pink, Color.orange,
        Color.white, Color.magenta, Color.red
        };
   private int[][] posicionArranque;
   protected int cantidadJugadores=0;

   public static void main(String[] args){
        new Server();
    }

    public Server() {
        lienzo=new Lienzo();
        hilo=new Thread(this);
        t = new CargadorArchivo();
        menu = new MenuServer(this);
       
        
       try {
           java.rmi.registry.LocateRegistry.createRegistry(1099);
           registry = LocateRegistry.getRegistry();
           System.out.println("RMI registry ready.");
       } catch (Exception e) {
           try {
                registry = LocateRegistry.getRegistry();
                System.out.println("RMI registry ready.");
            } catch (RemoteException ex) {
                System.out.println("Exception starting RMI registry:");
            }
       }
         
   }

    protected void startGame(){

            juego = menu.getGameName();
            posicionArranque=t.cargaArchivo(lienzo,null,menu.getGameMap());
        try {
            stub = (ServerInt) UnicastRemoteObject.exportObject(this, 0);
            // Bind the remote object's stub in the registry
            registry.bind(juego, stub);//Juego podría ser el juego actual
            System.out.println("Server ready");
            menu.setGameName(juego);
            menu.setSatus("Jugando");
            flagDeHilo = true;
            hilo.start();
        } catch (Exception e) {
            System.err.println("Server exception: " + e.toString());
            menu.setSatus("El nombre de juego " + juego+ " ya existe!!");
            menu.setStartGameEnabled(true);
        }
    }
     
     public synchronized void accion(ClientInt c, Object tecla) throws RemoteException {
         char te=tecla.toString().charAt(0);
         switch(te){
             case '0':
                  try {
                    rel.get(c.getUserName()).setDyO(-4,3);
                  } catch (RemoteException ex) {
                    Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                 }
                 break;
             case'1':
                 try {
                        rel.get(c.getUserName()).setDyO(4,1);
                     } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'2':
                 try {
                        rel.get(c.getUserName()).setDxO(-4,2);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'3':
                 try {
                        rel.get(c.getUserName()).setDxO(4,0);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'4':
                 try {
                        rel.get(c.getUserName()).setDy(0);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'5':
                 try {
                        rel.get(c.getUserName()).setDy(0);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'6':
                 try {
                        rel.get(c.getUserName()).setDx(0);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'7':
                 try {
                        rel.get(c.getUserName()).setDx(0);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'8':
                 try {
                        rel.get(c.getUserName()).setDisparar(true);
                       } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             case'9':
                 try {
                        rel.get(c.getUserName()).setDisparar(false);
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }
                 break;
             default:
                 break;
         }
       }
    
    public synchronized void register(ClientInt c) throws RemoteException {
        // synchronized porque lo necesita
        //cantidadJugadores,listaDeClientes, lienzo, rel
        listaDeClientes.addObserver(c);
        System.out.println("New Jugador: "+c.getUserName());
        c.recibirMapa(lienzo.getF());
        int pos =  cantidadJugadores % 9;
        Figura ff=new Movil(posicionArranque[pos][0],posicionArranque[pos][1],20,20, colores[pos], lienzo);
        ff.setNombre(c.getUserName());
        rel.put(c.getUserName(),ff);
        lienzo.getF2().add(ff);
        cantidadJugadores++;
    }


    @SuppressWarnings("static-access")
    public void run() {
         Vector<String> vivos = new Vector<String>();
         long tInicial=0;
         int tSleep=1;
         while(flagDeHilo){
            try {
                this.hilo.sleep(tSleep);
                int cuenta=0;
                tInicial=System.currentTimeMillis();
                
                synchronized(this){ //Es el mismo lock que usan los métodos sincronizados
                    for(int i=0;i<lienzo.getF2().size();i++)
                        lienzo.getF2().get(i).movete();

                    for(int i=0;i<lienzo.getF2().size();i++){
                        if(lienzo.getF2().get(i).toString().equals("Movil")){
                             Figura iv= new InformacionVidas(80,20,lienzo.getF2().get(i).getNombre(),lienzo.getF2().get(i).getvida(),lienzo.getF2().get(i).getColor(),lienzo);
                             iv.setNombre(lienzo.getF2().get(i).getNombre());
                             lienzo.getF2().add(iv);
                             cuenta++;
                         }
                    }
                    try {
                        vivos=listaDeClientes.notifyObservers(lienzo.getF2());
                        menu.setSatus("Jugando "+ vivos.size()+ " Jugadores ");
                    } catch (RemoteException ex) {
                        Logger.getLogger(Server.class.getName()).log(Level.SEVERE, null, ex);
                    }

                    for(int i=0;i<lienzo.getF2().size();i++){
                        if(lienzo.getF2().get(i).toString().equals("InformacionVidas")){
                            lienzo.getF2().remove(lienzo.getF2().get(i));
                        }
                     }


                    for(int i=0;i<lienzo.getF2().size();i++){
                        if(lienzo.getF2().get(i).toString().equals("Movil") && vivos.contains(lienzo.getF2().get(i).getNombre())==false){
                            try {
                                rel.remove(lienzo.getF2().get(i).getNombre());
                                lienzo.getF2().remove(lienzo.getF2().get(i));
                            } catch (Exception ex) {  }
                        }
                    }
                }

                tSleep = (100-(int)(System.currentTimeMillis()-tInicial));

               if(tSleep<1)
                   tSleep=1;
            } catch (InterruptedException ex) { }
        }
    }
}
